home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / INTERNET / SITES / LITTLE / P3SRC.ZIP / ATARI / BSPHERE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-18  |  13.6 KB  |  675 lines

  1. /*****************************************************************************
  2. *                bsphere.c
  3. *
  4. *  This module implements the bounding sphere calculations.
  5. *
  6. *  from Persistence of Vision(tm) Ray Tracer
  7. *  Copyright 1996 Persistence of Vision Team
  8. *---------------------------------------------------------------------------
  9. *  NOTICE: This source code file is provided so that users may experiment
  10. *  with enhancements to POV-Ray and to port the software to platforms other
  11. *  than those supported by the POV-Ray Team.  There are strict rules under
  12. *  which you are permitted to use this file.  The rules are in the file
  13. *  named POVLEGAL.DOC which should be distributed with this file. If
  14. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  15. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  16. *  Forum.  The latest version of POV-Ray may be found there as well.
  17. *
  18. * This program is based on the popular DKB raytracer version 2.12.
  19. * DKBTrace was originally written by David K. Buck.
  20. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  21. *
  22. *****************************************************************************/
  23.  
  24. #include "frame.h"
  25. #include "vector.h"
  26. #include "povproto.h"
  27. #include "bsphere.h"
  28.  
  29.  
  30.  
  31. /*****************************************************************************
  32. * Local preprocessor defines
  33. ******************************************************************************/
  34.  
  35. #define BRANCHING_FACTOR 4
  36.  
  37.  
  38.  
  39. /*****************************************************************************
  40. * Local typedefs
  41. ******************************************************************************/
  42.  
  43.  
  44.  
  45. /*****************************************************************************
  46. * Local variables
  47. ******************************************************************************/
  48.  
  49. static int maxelements, Axis;
  50.  
  51.  
  52.  
  53. /*****************************************************************************
  54. * Static functions
  55. ******************************************************************************/
  56.  
  57. static void merge_spheres PARAMS((VECTOR C, DBL *r, VECTOR C1, DBL r1, VECTOR C2, DBL r2));
  58. static void recompute_bound PARAMS((BSPHERE_TREE *Node));
  59.  
  60. static int find_axis PARAMS((BSPHERE_TREE **Elements, int first, int last));
  61. static void build_area_table PARAMS((BSPHERE_TREE **Elements, int a, int b, DBL *areas));
  62. static int sort_and_split PARAMS((BSPHERE_TREE **Root, BSPHERE_TREE **Elements, int *nElem, int first, int last));
  63.  
  64. static int CDECL comp_elements PARAMS((CONST void *in_a, CONST void *in_b));
  65.  
  66.  
  67.  
  68. /*****************************************************************************
  69. *
  70. * FUNCTION
  71. *
  72. *   merge_spheres
  73. *
  74. * INPUT
  75. *
  76. *   C, r           - Center and radius^2 of new sphere
  77. *   C1, r1, C2, r2 - Centers and radii^2 of spheres to merge
  78. *   
  79. * OUTPUT
  80. *
  81. *   C, r
  82. *   
  83. * RETURNS
  84. *   
  85. * AUTHOR
  86. *
  87. *   Dieter Bayer
  88. *   
  89. * DESCRIPTION
  90. *
  91. *   Calculate a sphere that encloses two given spheres.
  92. *
  93. * CHANGES
  94. *
  95. *   Jul 1994 : Creation.
  96. *
  97. *   Oct 1994 : Added test for enclosed spheres. Calculate optimal sphere. [DB]
  98. *
  99. ******************************************************************************/
  100.  
  101. static void merge_spheres(C, r, C1, r1, C2, r2)
  102. VECTOR C, C1, C2;
  103. DBL *r, r1, r2;
  104. {
  105.   DBL l, r1r, r2r, k1, k2;
  106.   VECTOR D;
  107.   DBL rdiv;
  108.   
  109.   VSub(D, C1, C2);
  110.  
  111.   VLength(l, D);
  112.  
  113.   /* Check if one sphere encloses the other. */
  114.  
  115.   r1r = sqrt(r1);
  116.   r2r = sqrt(r2);
  117.  
  118.   if (l + r1r <= r2r)
  119.   {
  120.     Assign_Vector(C, C2);
  121.  
  122.     *r = r2;
  123.  
  124.     return;
  125.   }
  126.  
  127.   if (l + r2r <= r1r)
  128.   {
  129.     Assign_Vector(C, C1);
  130.  
  131.     *r = r1;
  132.  
  133.     return;
  134.   }
  135.   
  136.   rdiv = (1.0 / l);
  137.   k1 = (1.0 + (r1r - r2r) * rdiv) / 2.0;
  138.   k2 = (1.0 + (r2r - r1r) * rdiv) / 2.0;
  139.  
  140. /*
  141.   k1 = (1.0 + (r1r - r2r) / l) / 2.0;
  142.   k2 = (1.0 + (r2r - r1r) / l) / 2.0;
  143. */
  144.  
  145.   VLinComb2(C, k1, C1, k2, C2);
  146.  
  147.   *r = Sqr((l + r1r + r2r) / 2.0);
  148. }
  149.  
  150.  
  151.  
  152. /*****************************************************************************
  153. *
  154. * FUNCTION
  155. *
  156. *   recompute_bound
  157. *
  158. * INPUT
  159. *
  160. *   Node - Pointer to node
  161. *
  162. * OUTPUT
  163. *
  164. *   Node
  165. *
  166. * RETURNS
  167. *
  168. * AUTHOR
  169. *
  170. *   Dieter Bayer
  171. *
  172. * DESCRIPTION
  173. *
  174. *   Recompute the bounding sphere of a given node in the bounding hierarchy,
  175. *   i. e. find the bounding sphere that encloses the bounding spheres
  176. *   of all nodes.
  177. *
  178. *   NOTE: The sphere found is probably not the tightest sphere possible!
  179. *
  180. * CHANGES
  181. *
  182. *   Jul 1994 : Creation.
  183. *
  184. *   Oct 1994 : Improved bounding sphere calculation. [DB]
  185. *
  186. ******************************************************************************/
  187.  
  188. static void recompute_bound(Node)
  189. BSPHERE_TREE *Node;
  190. {
  191.   short i;
  192.   DBL r2;
  193.   VECTOR C;
  194.  
  195.   COOPERATE_1
  196.  
  197.   Assign_Vector(C, Node->Node[0]->C);
  198.  
  199.   r2 = Node->Node[0]->r2;
  200.  
  201.   for (i = 1; i < Node->Entries; i++)
  202.   {
  203.     merge_spheres(C, &r2, C, r2, Node->Node[i]->C, Node->Node[i]->r2);
  204.   }
  205.  
  206.   Assign_Vector(Node->C, C);
  207.  
  208.   Node->r2 = r2;
  209. }
  210.  
  211.  
  212.  
  213. /*****************************************************************************
  214. *
  215. * FUNCTION
  216. *
  217. *   comp_elements
  218. *
  219. * INPUT
  220. *
  221. *   in_a, in_b - elements to compare
  222. *
  223. * OUTPUT
  224. *
  225. * RETURNS
  226. *
  227. *   int - result of comparison
  228. *
  229. * AUTHOR
  230. *
  231. *   Dieter Bayer
  232. *
  233. * DESCRIPTION
  234. *
  235. *   -
  236. *
  237. * CHANGES
  238. *
  239. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  240. *
  241. ******************************************************************************/
  242.  
  243. static int CDECL comp_elements(in_a, in_b)
  244. CONST void *in_a;
  245. CONST void *in_b;
  246. {
  247.   DBL am, bm;
  248.  
  249.   am = (*(BSPHERE_TREE **)in_a)->C[Axis];
  250.   bm = (*(BSPHERE_TREE **)in_b)->C[Axis];
  251.  
  252.   if (am < bm - EPSILON)
  253.   {
  254.     return (-1);
  255.   }
  256.   else
  257.   {
  258.     if (am > bm + EPSILON)
  259.     {
  260.       return (1);
  261.     }
  262.     else
  263.     {
  264.       return (0);
  265.     }
  266.   }
  267. }
  268.  
  269.  
  270.  
  271. /*****************************************************************************
  272. *
  273. * FUNCTION
  274. *
  275. *   find_axis
  276. *
  277. * INPUT
  278. *
  279. * OUTPUT
  280. *
  281. * RETURNS
  282. *
  283. * AUTHOR
  284. *
  285. *   Dieter Bayer
  286. *
  287. * DESCRIPTION
  288. *
  289. *   -
  290. *
  291. * CHANGES
  292. *
  293. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  294. *
  295. ******************************************************************************/
  296.  
  297. static int find_axis(Elements, first, last)
  298. BSPHERE_TREE **Elements;
  299. int first, last;
  300. {
  301.   int which = X;
  302.   int i;
  303.   DBL e, d = - BOUND_HUGE;
  304.   VECTOR C, mins, maxs;
  305.  
  306.   Make_Vector(mins,  BOUND_HUGE,  BOUND_HUGE,  BOUND_HUGE);
  307.   Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
  308.  
  309.   for (i = first; i < last; i++)
  310.   {
  311.     Assign_Vector(C, Elements[i]->C);
  312.  
  313.     mins[X] = min(mins[X], C[X]);
  314.     maxs[X] = max(maxs[X], C[X]);
  315.  
  316.     mins[Y] = min(mins[Y], C[Y]);
  317.     maxs[Y] = max(maxs[Y], C[Y]);
  318.  
  319.     mins[Z] = min(mins[Z], C[Z]);
  320.     maxs[Z] = max(maxs[Z], C[Z]);
  321.   }
  322.  
  323.   e = maxs[X] - mins[X];
  324.  
  325.   if (e > d)
  326.   {
  327.     d = e;  which = X;
  328.   }
  329.  
  330.   e = maxs[Y] - mins[Y];
  331.  
  332.   if (e > d)
  333.   {
  334.     d = e;  which = Y;
  335.   }
  336.  
  337.   e = maxs[Z] - mins[Z];
  338.  
  339.   if (e > d)
  340.   {
  341.     which = Z;
  342.   }
  343.  
  344.   return (which);
  345. }
  346.  
  347.  
  348.  
  349. /*****************************************************************************
  350. *
  351. * FUNCTION
  352. *
  353. *   build_area_table
  354. *
  355. * INPUT
  356. *
  357. * OUTPUT
  358. *
  359. * RETURNS
  360. *
  361. * AUTHOR
  362. *
  363. *   Dieter Bayer
  364. *
  365. * DESCRIPTION
  366. *
  367. *   Generates a table of bounding sphere surface areas.
  368. *
  369. * CHANGES
  370. *
  371. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  372. *
  373. ******************************************************************************/
  374.  
  375. static void build_area_table(Elements, a, b, areas)
  376. BSPHERE_TREE **Elements;
  377. int a, b;
  378. DBL *areas;
  379. {
  380.   int i, imin, dir;
  381.   DBL r2;
  382.   VECTOR C;
  383.  
  384.   if (a < b)
  385.   {
  386.     imin = a;  dir = 1;
  387.   }
  388.   else
  389.   {
  390.     imin = b;  dir = -1;
  391.   }
  392.  
  393.   Assign_Vector(C, Elements[a]->C);
  394.  
  395.   r2 = Elements[a]->r2;
  396.  
  397.   for (i = a; i != (b + dir); i += dir)
  398.   {
  399.     merge_spheres(C, &r2, C, r2, Elements[i]->C, Elements[i]->r2);
  400.  
  401.     areas[i-imin] = r2;
  402.   }
  403. }
  404.  
  405.  
  406.  
  407. /*****************************************************************************
  408. *
  409. * FUNCTION
  410. *
  411. *   sort_and_split
  412. *
  413. * INPUT
  414. *
  415. * OUTPUT
  416. *
  417. * RETURNS
  418. *
  419. * AUTHOR
  420. *
  421. *   Dieter Bayer
  422. *
  423. * DESCRIPTION
  424. *
  425. *   -
  426. *
  427. * CHANGES
  428. *
  429. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  430. *
  431. ******************************************************************************/
  432.  
  433. static int sort_and_split(Root, Elements, nElem, first, last)
  434. BSPHERE_TREE **Root;
  435. BSPHERE_TREE **Elements;
  436. int *nElem, first, last;
  437. {
  438.   int size, i, best_loc;
  439.   DBL *area_left, *area_right;
  440.   DBL best_index, new_index;
  441.   BSPHERE_TREE *cd;
  442.  
  443.   Axis = find_axis(Elements, first, last);
  444.  
  445.   size = last - first;
  446.  
  447.   if (size <= 0)
  448.   {
  449.     return (1);
  450.   }
  451.  
  452.   /*
  453.    * Actually, we could do this faster in several ways. We could use a
  454.    * logn algorithm to find the median along the given axis, and then a
  455.    * linear algorithm to partition along the axis. Oh well.
  456.    */
  457.  
  458.   QSORT((void *)(&Elements[first]), (size_t)size, sizeof(BSPHERE_TREE *), comp_elements);
  459.  
  460.   /*
  461.    * area_left[] and area_right[] hold the surface areas of the bounding
  462.    * boxes to the left and right of any given point. E.g. area_left[i] holds
  463.    * the surface area of the bounding box containing Elements 0 through i and
  464.    * area_right[i] holds the surface area of the box containing Elements
  465.    * i through size-1.
  466.    */
  467.  
  468.   area_left  = (DBL *)POV_MALLOC(size * sizeof(DBL), "blob bounding hierarchy");
  469.   area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "blob bounding hierarchy");
  470.  
  471.   /* Precalculate the areas for speed. */
  472.  
  473.   build_area_table(Elements, first, last - 1, area_left);
  474.   build_area_table(Elements, last - 1, first, area_right);
  475.  
  476.   best_index = area_right[0] * (size - 3.0);
  477.  
  478.   best_loc = - 1;
  479.  
  480.   /*
  481.    * Find the most effective point to split. The best location will be
  482.    * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
  483.    * are the number of objects in the two groups and A1 and A2 are the
  484.    * surface areas of the bounding boxes of the two groups.
  485.    */
  486.  
  487.   for (i = 0; i < size - 1; i++)
  488.   {
  489.     new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1];
  490.  
  491.     if (new_index < best_index)
  492.     {
  493.       best_index = new_index;
  494.       best_loc = i + first;
  495.     }
  496.   }
  497.  
  498.   POV_FREE(area_left);
  499.   POV_FREE(area_right);
  500.  
  501.   /*
  502.    * Stop splitting if the BRANCHING_FACTOR is reached or
  503.    * if splitting stops being effective.
  504.    */
  505.  
  506.   if ((size <= BRANCHING_FACTOR) || (best_loc < 0))
  507.   {
  508.     cd = (BSPHERE_TREE *)POV_MALLOC(sizeof(BSPHERE_TREE), "blob bounding hierarchy");
  509.  
  510.     cd->Entries = (short)size;
  511.  
  512.     cd->Node = (BSPHERE_TREE **)POV_MALLOC(size*sizeof(BSPHERE_TREE *), "blob bounding hierarchy");
  513.  
  514.     for (i = 0; i < size; i++)
  515.     {
  516.       cd->Node[i] = Elements[first+i];
  517.     }
  518.  
  519.     recompute_bound(cd);
  520.  
  521.     *Root = cd;
  522.  
  523.     if (*nElem > maxelements)
  524.     {
  525.       /* Prim array overrun, increase array by 50%. */
  526.  
  527.       maxelements = 1.5 * maxelements;
  528.  
  529.       /* For debugging only. */
  530.  
  531.       Debug_Info("Reallocing elements to %d\n", maxelements);
  532.  
  533.       Elements = (BSPHERE_TREE **)POV_REALLOC(Elements, maxelements * sizeof(BSPHERE_TREE *), "bounding slabs");
  534.     }
  535.  
  536.     Elements[*nElem] = cd;
  537.  
  538.     (*nElem)++;
  539.  
  540.     return (1);
  541.   }
  542.   else
  543.   {
  544.     sort_and_split(Root, Elements, nElem, first, best_loc + 1);
  545.  
  546.     sort_and_split(Root, Elements, nElem, best_loc + 1, last);
  547.  
  548.     return (0);
  549.   }
  550. }
  551.  
  552.  
  553.  
  554. /*****************************************************************************
  555. *
  556. * FUNCTION
  557. *
  558. *   Build_Bounding_Sphere_Hierarchy
  559. *
  560. * INPUT
  561. *
  562. *   nElem    - number of elements in Elements
  563. *   Elements - array containing nElem elements
  564. *
  565. * OUTPUT
  566. *
  567. *   Root     - root node of the hierarchy
  568. *
  569. * RETURNS
  570. *
  571. * AUTHOR
  572. *
  573. *   Dieter Bayer
  574. *
  575. * DESCRIPTION
  576. *
  577. *   Create the bounding sphere hierarchy for a given set of elements.
  578. *   One element consists of an element number (index into the array
  579. *   of elements; e.g. blob components, triangles) and a bounding
  580. *   sphere enclosing this element (center and squared radius).
  581. *
  582. * CHANGES
  583. *
  584. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  585. *
  586. ******************************************************************************/
  587.  
  588. void Build_Bounding_Sphere_Hierarchy(Root, nElem, Elements)
  589. int nElem;
  590. BSPHERE_TREE **Root, **Elements;
  591. {
  592.   int low, high;
  593.  
  594.   /*
  595.    * This is a resonable guess at the number of elements needed.
  596.    * This array will be reallocated as needed if it isn't.
  597.    */
  598.  
  599.   maxelements = 2 * nElem;
  600.  
  601.   /*
  602.    * Do a sort on the elements, with the end result being
  603.    * a tree of objects sorted along the x, y, and z axes.
  604.    */
  605.  
  606.   if (nElem > 0)
  607.   {
  608.     low  = 0;
  609.     high = nElem;
  610.  
  611.     while (sort_and_split(Root, Elements, &nElem, low, high) == 0)
  612.     {
  613.       low  = high;
  614.       high = nElem;
  615.     }
  616.   }
  617. }
  618.  
  619.  
  620.  
  621. /*****************************************************************************
  622. *
  623. * FUNCTION
  624. *
  625. *   Destroy_Bounding_Sphere_Hierarchy
  626. *
  627. * INPUT
  628. *
  629. *   Node - Pointer to current node
  630. *
  631. * OUTPUT
  632. *
  633. *   Node
  634. *
  635. * RETURNS
  636. *
  637. * AUTHOR
  638. *
  639. *   Dieter Bayer
  640. *
  641. * DESCRIPTION
  642. *
  643. *   Destroy bounding sphere hierarchy.
  644. *
  645. * CHANGES
  646. *
  647. *   Aug 1994 : Creation.
  648. *
  649. *   Dec 1994 : Fixed memory leakage. [DB]
  650. *
  651. ******************************************************************************/
  652.  
  653. void Destroy_Bounding_Sphere_Hierarchy(Node)
  654. BSPHERE_TREE *Node;
  655. {
  656.   short i;
  657.  
  658.   if (Node != NULL)
  659.   {
  660.     if (Node->Entries > 0)
  661.     {
  662.       /* This is a node. Free sub-nodes. */
  663.  
  664.       for (i = 0; i < Node->Entries; i++)
  665.       {
  666.         Destroy_Bounding_Sphere_Hierarchy(Node->Node[i]);
  667.       }
  668.  
  669.       POV_FREE(Node->Node);
  670.     }
  671.  
  672.     POV_FREE(Node);
  673.   }
  674. }
  675.